# Telnet acquisition of moorings data
#
# Author: David Goldsmith, Wash. State Dept. of Ecology, dgol461@ecy.wa.gov
# Original release date: < 9/15/2011

import sys
import array as A
import datetime as DT
from time import *
from os import linesep
from dateutil.parser import parse as dateparse
from telnetlib import Telnet as T
from socket import timeout

class getdata(object):
    def __init__(self, ipport, out, logging,
                  Max=20, writeOut=1,
                  prompt=["S>", "<Executed/>"]):
        self.host, self.port = ipport
        self.out = out
        self.logging = logging
        self.max = Max
        self.prompt = prompt
        self.writeOut = writeOut

    def write_progress(self, progress_code):#, delay=5):
        self.out.write(progress_code + linesep)
##        if self.host == "166.130.17.242": # if we're talking to Wilapa
##            sleep(delay)
        self.out.flush()

##    def write_data(self, data):
##        self.out.write(data + linesep)
##        if self.host == "166.130.17.242": # if we're talking to Wilapa
##            sleep(self.max)
##        self.out.flush()

    def getdata(self, hours2sample, offset):
        NS = int(4 * hours2sample) # There are 4 samples per hour
        offset = int(4 * offset)
        attempts = 1
        prompt = self.prompt; Max = self.max
        tn = T(self.host, self.port, Max)
        tn.write("\r\n")
        tries = 0
        idx, ju, nk = tn.expect(prompt, Max)
        while (idx < 0) or ((prompt[idx] not in prompt) and (tries < Max)):
            # try sending Esc
            tn.write(chr(27))
            sleep(5)
            tn.write("\r\n")
            idx, ju, nk = tn.expect(prompt, Max)
            tries += 1
        if tries == Max:
            return ("Couldn't get a prompt", None, None, None)
    # Send stop, wait for prompt, send ds, wait for "logging" to be in reply
    # Note: presence of logging in reply does not guarantee the stop was successful,
    # thus the need for the while loop which follows
        prompt = prompt[idx]
        if self.writeOut:
            self.write_progress("Connection established, issuing stop command")
        tn.write("stop\r\n")
        tn.read_until(prompt, Max)
        tn.write("ds\r\n")
        ju, nk, up2match = tn.expect(["logging"], Max);
    # Get type (16 or 37)
        type_determiner = up2match.split('V')[0]
        if "16" in type_determiner:
            typ = "16"
        elif "37" in type_determiner:
            typ = "37"
        else:
            return ("Sorry!  Instrument type not recognized!", None, None, None)
        if self.writeOut:
            self.write_progress(typ)
    # Now issue stop followed by ds until "not logging" is in reply, or there
    # have been Max unsuccessful attempts
        while ("not logging" not in up2match) and (attempts < Max):
            attempts += 1
            tn.write("stop\r\n")
            tn.read_until(prompt, Max)
            tn.write("ds\r\n")
            ju, nk, up2match = tn.expect(["logging"], Max)
        if attempts >= Max: # if there were too many attempts
            return ("Sorry!  Couldn't stop logging.", None, None, None)
        self.logging = False
        if self.writeOut:
            self.write_progress("ds returned a status of not logging, proceeding")
        tn.write("\r\n")
        tn.read_until(prompt, Max);
        if self.writeOut:
            self.write_progress("Computer (UTC) time: " + strftime('%m-%d-%Y %H:%M:%S', gmtime()))
        tn.write("ds\r\n")
#        if (self.host == "166.140.038.220") and (self.port == 4002):
        ju, nk, tmp = tn.expect(["\d\d\s\w\w\w\s\d\d\d\d", "\d\d-\d\d-\d\d\d\d"], Max)
#        else:
#            ju, nk, tmp = tn.expect(["\d\d\s\w\w\w\s\d\d\d\d"], Max)
        if self.writeOut:
            self.write_progress(tmp)
        date = dateparse(tmp[-11:])
        if date is None:
            return ("Sorry!  dateparse failed!", None, None, None)
        tmp = tn.read_until("\r\n", Max)
        if self.writeOut:
            self.write_progress("Time = " + tmp)
        time = dateparse(tmp[-10:-3])
        if "16" in typ:
            lookfor = "samples = "
        else:
            lookfor = "samplenumber = "
        data = tn.read_until(lookfor, Max)
        if self.writeOut:
            self.write_progress(data)
        tmp = tn.read_until(',', Max)
        if self.writeOut:
            self.write_progress(tmp)
        ns = int(tmp.strip(','), 10)
    # have number of samples, get rest of header...
        data = tn.read_until(prompt, Max)
        if self.writeOut:
            self.write_progress(data)
    # ...make sure we're in decimal mode...
        if "16" in typ:
            fmtcmd = "outputformat=3\r\n"
        elif prompt=="S>":
            fmtcmd = "format=2\r\n"
        else:
            fmtcmd = ""
        if fmtcmd:
            tn.write(fmtcmd)
        tn.read_until(prompt, Max)
    # ...and get the decimal data
        if (ns - offset < 0) or (offset < 0):
            raise
        range = "dd0," + str(ns-offset) + "\r\n" # this is the default
        if ns-offset-NS >= 0: # this is the more likely event
            range = "dd" + str(ns-offset-NS+1) + "," + str(ns-offset) + "\r\n"
        tn.write(range)
        data = tn.read_until(prompt)
        if self.writeOut:
            self.write_progress(data)
        last_dt = data[-25:-7]
    # now get hex data
        if prompt != "S>":
            tn.write("QS\r\n")
            return (tn, date, time, last_dt)
        elif "16" in typ:
            fmtcmd = "outputformat=1\r\n"
        else:
            fmtcmd = "format=0\r\n"
        tn.write(fmtcmd) # change the output format to hex
        data = tn.read_until(prompt)
        if self.writeOut:
            self.write_progress(data)
        tn.write(range)
        data = tn.read_until(prompt)
        if self.writeOut:
            self.write_progress(data)
        if "16" in typ:
            fmtcmd = "outputformat=3\r\n"
        else:
            fmtcmd = "format=2\r\n"
        tn.write(fmtcmd) # change the output format back to dec
        data = tn.read_until(prompt)
        if self.writeOut:
            self.write_progress(data)
        return (tn, date, time, last_dt)